<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>智能助手聊天</title>
    <script src="js/vue.global.prod.js"></script>
    <script src="js/axios.min.js"></script>
    <link rel="stylesheet" href="js/github.min.css" />
    <script src="js/marked.min.js"></script>
    <script src="js/highlight.min.js"></script>
    <style>
        body {
         font-family: 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', Arial, sans-serif;
         background: linear-gradient(135deg, #e0e7ff 0%, #f5f5f5 100%);
       }
       html, body {
         height: 100%;
         margin: 0;
         padding: 0;
       }
       #app {
         width: 100vw;
         height: 100vh;
         margin: 0;
         background: #fff;
         box-shadow: none;
         display: flex;
         overflow: hidden;
       }
       .sidebar {
         width: 240px;
         background: #f3f6fd;
         border-right: 1.5px solid #e3e8f0;
         padding: 32px 18px 24px 18px;
         box-sizing: border-box;
         display: flex;
         flex-direction: column;
         gap: 32px;
         height: 100vh;
       }
       .main {
         flex: 1;
         display: flex;
         flex-direction: column;
         padding: 36px 36px 24px 36px;
         background: #fafdff;
         min-height: 100vh;
         height: 100vh;
         box-sizing: border-box;
       }
       .chat-history {
         flex: 1;
         overflow-y: auto;
         margin-bottom: 18px;
         border: 1.5px solid #e3e8f0;
         border-radius: 8px;
         background: #f7faff;
         padding: 18px 16px 18px 16px;
         box-shadow: 0 1px 4px #0001;
         scrollbar-width: thin;
         scrollbar-color: #b3c6e0 #f7faff;
       }
       .chat-history::-webkit-scrollbar {
         width: 8px;
       }
       .chat-history::-webkit-scrollbar-thumb {
         background: #b3c6e0;
         border-radius: 4px;
       }
       .chat-item {
         margin-bottom: 18px;
         display: flex;
         flex-direction: column;
         align-items: flex-start;
       }
       .chat-item.user {
         align-items: flex-end;
       }
       .chat-bubble {
         display: inline-block;
         padding: 12px 18px;
         border-radius: 18px;
         max-width: 80%;
         font-size: 16px;
         line-height: 1.7;
         box-shadow: 0 1px 4px #0001;
         margin-bottom: 2px;
         word-break: break-word;
       }
       .chat-item.user .chat-bubble {
         background: #fff9e3;
         color: #7a5a00;
         border-bottom-right-radius: 6px;
         border: 1.5px solid #f5e1a4;
         box-shadow: 0 2px 8px #f5e1a455;
       }
       .chat-item.assistant .chat-bubble {
         background: #fdf6e3;
         color: #7a5a00;
         border-bottom-left-radius: 6px;
         border: 1.5px solid #f5e1a4;
         box-shadow: 0 2px 8px #f5e1a433;
       }
       .chat-item.error .chat-bubble {
         background: #fff0f0;
         color: #d32f2f;
         border: 1px solid #fbb;
       }
       .chat-item .role {
         font-weight: bold;
         margin-bottom: 2px;
         font-size: 13px;
         color: #888;
       }
       .domain-select label,
       .history-list label {
         display: block;
         margin-bottom: 6px;
         font-size: 15px;
         color: #1976d2;
         font-weight: 600;
       }
       .domain-select select,
       .history-list select {
         width: 100%;
         margin-bottom: 14px;
         padding: 7px 10px;
         border-radius: 6px;
         border: 1.2px solid #b3c6e0;
         background: #fafdff;
         font-size: 15px;
       }
       .input-row {
         display: flex;
         gap: 10px;
       }
       .input-row input {
         flex: 1;
         padding: 12px 14px;
         border-radius: 8px;
         border: 1.5px solid #b3c6e0;
         font-size: 16px;
         background: #fff;
         transition: border 0.2s;
       }
       .input-row input:focus {
         border: 1.5px solid #1976d2;
         outline: none;
       }
       .input-row button {
         padding: 12px 28px;
         border-radius: 8px;
         border: none;
         background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
         color: #fff;
         font-size: 16px;
         font-weight: 600;
         cursor: pointer;
         box-shadow: 0 1px 4px #0001;
         transition: background 0.2s, box-shadow 0.2s;
       }
       .input-row button:disabled {
         background: #b3c6e0;
         color: #fff;
         cursor: not-allowed;
       }
       .input-row button:not(:disabled):hover {
         background: linear-gradient(135deg, #1565c0 60%, #1976d2 100%);
         box-shadow: 0 2px 8px #1976d233;
       }
       .history-item.active {
         background: #e3f2fd !important;
         border-color: #1976d2 !important;
         color: #1976d2;
         font-weight: bold;
       }
       .history-item {
         transition: background 0.2s, color 0.2s;
       }
       .history-item:hover {
         background: #f0f7ff;
       }
       .markdown-body pre {
         background: #f0f4fa;
         padding: 14px;
         overflow-x: auto;
         border-radius: 6px;
         margin-bottom: 1em;
       }
       .markdown-body code {
         font-family: Consolas, Monaco, monospace;
         font-size: 15px;
         line-height: 1.6;
         color: #2d2d2d;
       }
       .user-info {
         color: #1976d2;
         font-size: 16px;
         font-weight: 600;
       }
       .user-bar {
         position: absolute;
         top: 18px;
         right: 36px;
         z-index: 20;
         display: flex;
         align-items: center;
         gap: 12px;
       }
       .user-bar .user-info {
         color: #1976d2;
         font-size: 16px;
         font-weight: 600;
       }
       .login-btn, .logout-btn {
         padding: 6px 18px;
         border-radius: 6px;
         border: none;
         background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
         color: #fff;
         font-size: 15px;
         font-weight: 600;
         cursor: pointer;
         box-shadow: 0 1px 4px #0001;
         transition: background 0.2s, box-shadow 0.2s;
       }
       .login-btn:hover, .logout-btn:hover {
         background: linear-gradient(135deg, #1565c0 60%, #1976d2 100%);
       }
       .auth-modal {
         position: fixed;
         z-index: 1000;
         left: 0; top: 0; right: 0; bottom: 0;
         background: rgba(0,0,0,0.18);
         display: flex;
         align-items: center;
         justify-content: center;
       }
       .auth-box {
         position: relative;
         background: #fff;
         border-radius: 12px;
         box-shadow: 0 4px 32px #0002;
         padding: 36px 32px 28px 32px;
         min-width: 320px;
         max-width: 90vw;
         width: 350px;
         display: flex;
         flex-direction: column;
         align-items: stretch;
       }
       .auth-box h2 {
         text-align: center;
         margin-bottom: 18px;
         color: #1976d2;
       }
       .auth-box form {
         display: flex;
         flex-direction: column;
         gap: 12px;
         margin-bottom: 8px;
       }
       .auth-box input {
         padding: 10px 12px;
         border-radius: 6px;
         border: 1.2px solid #b3c6e0;
         font-size: 16px;
       }
       .auth-box button {
         padding: 10px 0;
         border-radius: 6px;
         border: none;
         background: linear-gradient(135deg, #1976d2 60%, #42a5f5 100%);
         color: #fff;
         font-size: 16px;
         font-weight: 600;
         cursor: pointer;
         margin-bottom: 8px;
       }
       .auth-box button:disabled {
         background: #b3c6e0;
         color: #fff;
         cursor: not-allowed;
       }
       .auth-switch {
         text-align: center;
         font-size: 14px;
         margin-top: 2px;
       }
       .auth-switch a {
         color: #1976d2;
         cursor: pointer;
         text-decoration: underline;
       }
       .auth-error {
         color: #d32f2f;
         text-align: center;
         margin-top: 8px;
         font-size: 15px;
       }
       .auth-close {
         position: absolute;
         top: 12px;
         right: 16px;
         background: none;
         border: none;
         font-size: 26px;
         color: #888;
         cursor: pointer;
         z-index: 10;
         transition: color 0.2s;
       }
       .auth-close:hover {
         color: #1976d2;
       }
    </style>
</head>
<body>
<div id="app">
    <div class="user-bar">
        <template v-if="isLoggedIn">
            <span class="user-info">欢迎，{{ userInfo }}</span>
            <button class="logout-btn" @click="logout">退出</button>
        </template>
        <template v-else>
            <button class="login-btn" @click="showLogin">登录</button>
            <button class="login-btn" @click="showRegister">注册</button>
        </template>
    </div>
    <div class="sidebar">
        <div class="domain-select">
            <label for="domain-select">选择领域：</label>
            <select id="domain-select" v-model="selectedDomain" @change="onDomainChange">
                <option v-for="d in domains" :value="d.id" :key="d.id">{{ d.name }}</option>
            </select>
        </div>
        <div class="history-list">
            <label>历史会话：</label>
            <div >
                <div
                        v-for="c in filteredConversations"
                        :key="c.id"
                        :class="['history-item', { active: c.id === selectedConversation }]"
                        @click="selectConversation(c.id)"
                        style="padding: 6px 8px; cursor: pointer; border-radius: 4px; margin-bottom: 4px; background: #fff; border: 1px solid #eee;"
                >
                    {{ c.label }}
                </div>
                <div
                        :class="['history-item', { active: !selectedConversation }]"
                        @click="selectConversation('')"
                        style="padding: 6px 8px; cursor: pointer; border-radius: 4px; background: #f0f0f0; border: 1px dashed #ccc;"
                >
                    新会话
                </div>
            </div>
        </div>
    </div>
    <div class="main">
        <h2>智能助手聊天</h2>
        <div class="chat-history">
            <div v-for="(msg, idx) in chatHistory" :key="idx" :class="['chat-item', msg.role]">
                <span class="role">{{ msg.role === 'user' ? '我' : (msg.role === 'assistant' ? '助手' : (msg.role?.toLowerCase() === 'error' ? '系统' : '')) }}:</span>
                <div class="chat-bubble" v-if="msg.role !== 'assistant' && msg.role !== 'error'">{{ msg.content }}</div>
                <div class="chat-bubble" v-else v-html="renderMarkdown(msg.content)" :style="msg.role === 'error' ? 'color:red' : ''"></div>
            </div>
            <div v-if="loading" class="chat-item loading">
                <span style="color: #888">助手正在思考...</span>
            </div>
        </div>
        <form class="input-row" @submit.prevent="sendMessage">
            <input v-model="input" :disabled="loading || !selectedDomain" placeholder="请输入你的问题..." />
            <button :disabled="loading || !input || !selectedDomain">发送</button>
        </form>
    </div>
    <div v-if="showLoginModal" class="auth-modal">
        <div class="auth-box">
            <button class="auth-close" @click="showLoginModal=false" title="关闭">×</button>
            <h2 v-if="authMode==='login'">登录</h2>
            <h2 v-else>注册</h2>
            <form @submit.prevent="handleAuth">
                <input v-model="authForm.username" placeholder="用户名" required autocomplete="username" />
                <input v-model="authForm.password" type="password" placeholder="密码" required autocomplete="current-password" />
                <button type="submit" :disabled="authLoading">{{ authMode==='login' ? '登录' : '注册' }}</button>
            </form>
            <div class="auth-switch">
                <span v-if="authMode==='login'">没有账号？<a href="#" @click.prevent="authMode='register'">注册</a></span>
                <span v-else>已有账号？<a href="#" @click.prevent="authMode='login'">登录</a></span>
            </div>
            <div v-if="authError" class="auth-error">{{ authError }}</div>
        </div>
    </div>
</div>

<script>
    axios.defaults.withCredentials = true;
    const { createApp, ref, computed, watch } = Vue;
    createApp({
      setup() {
        const domains = ref([]);
        const selectedDomain = ref('');
        const conversations = ref([]);
        const selectedConversation = ref('');
        const chatHistory = ref([]);
        const input = ref('');
        const loading = ref(false);
        const userInfo = ref(localStorage.getItem('username') || '');
        const isLoggedIn = ref(localStorage.getItem('isLoggedIn') === '1');
        const showLoginModal = ref(false);
        const authMode = ref('login');
        const authForm = ref({ username: '', password: '' });
        const authLoading = ref(false);
        const authError = ref('');

        const filteredConversations = computed(() => {
          return conversations.value
            .filter((c) => c.domain === selectedDomain.value)
            .map((c) => {
              let firstUserMsg = '';
              if (c.messages) {
                try {
                  const arr = JSON.parse(c.messages);
                  const first = arr.find((m) => m.type?.toLowerCase() === 'user');
                  if (first) firstUserMsg = first.content;
                } catch {}
              }
              return { id: c.id, label: firstUserMsg || '(无内容)', domain: c.domain };
            });
        });

        const fetchDomains = async () => {
          const res = await axios.get('/account/mydomains');
          domains.value = res.data;
          if (domains.value.length > 0) selectedDomain.value = domains.value[0].id;
        };

        const fetchConversations = async () => {
          const res = await axios.get('/conversations');
          conversations.value = res.data;
        };

        const loadConversation = () => {
          chatHistory.value = [];
          if (!selectedConversation.value) return;
          const conv = conversations.value.find((c) => c.id === selectedConversation.value);
          if (conv?.messages) {
            try {
              const arr = JSON.parse(conv.messages);
              chatHistory.value = arr.map((m) => ({
                role: m.type ? m.type.toLowerCase() : '',
                content: m.content
              }));
            } catch {}
          }
        };

        const autoFormatMarkdown = (raw) => {
          const trimmed = raw.trim();
          const likelyCode =
            (trimmed.includes('class') || trimmed.includes('public static void main')) &&
            trimmed.includes('{') &&
            !trimmed.includes('```');
          if (likelyCode) {
            return '```java\n' + trimmed + '\n```';
          }
          return raw;
        };

        const sendMessage = async () => {
          if (!input.value || !selectedDomain.value) return;
          loading.value = true;
          try {
            const params = {
              question: input.value,
              domain: selectedDomain.value
            };
            if (selectedConversation.value) {
              params.cid = selectedConversation.value;
            }
            const res = await axios.post('/ask', null, { params });
            chatHistory.value.push({ role: 'user', content: input.value });
            const formatted = autoFormatMarkdown(res.data);
            chatHistory.value.push({ role: 'assistant', content: formatted });
            input.value = '';
            await fetchConversations();
            if (!selectedConversation.value) {
              const last = conversations.value.filter((c) => c.domain === selectedDomain.value).slice(-1)[0];
              if (last) selectedConversation.value = last.id;
            }
          } catch (err) {
            chatHistory.value.push({ role: 'error', content: err.response?.data || '发生错误，请稍后重试。' });
          } finally {
            loading.value = false;
          }
        };

        const onDomainChange = () => {
          selectedConversation.value = '';
          chatHistory.value = [];
        };

        const selectConversation = (id) => {
          selectedConversation.value = id;
          loadConversation();
        };

        const renderMarkdown = (content) => {
          if (!content) return '';
          const html =
            '<div class="markdown-body">' +
            window.marked.parse(content, {
              highlight: function (code, lang) {
                if (window.hljs && lang && window.hljs.getLanguage(lang)) {
                  return window.hljs.highlight(code, { language: lang }).value;
                }
                return code;
              }
            }) +
            '</div>';
          setTimeout(() => {
            if (window.hljs) {
              document.querySelectorAll('pre code').forEach((block) => {
                window.hljs.highlightElement(block);
              });
            }
          }, 0);
          return html;
        };

        const showLogin = () => {
          authMode.value = 'login';
          showLoginModal.value = true;
        };

        const showRegister = () => {
          authMode.value = 'register';
          showLoginModal.value = true;
        };

        const logout = () => {
          localStorage.removeItem('isLoggedIn');
          localStorage.removeItem('username');
          userInfo.value = '';
          isLoggedIn.value = false;
          location.reload();
        };

        const doLogin = async () => {
          authLoading.value = true;
          try {
            const res = await axios.post('/login', null, {
              params: {
                username: authForm.value.username,
                password: authForm.value.password
              }
            });
            userInfo.value = res.data.username;
            isLoggedIn.value = true;
            localStorage.setItem('isLoggedIn', '1');
            localStorage.setItem('username', res.data.username);
            showLoginModal.value = false;
            await fetchDomains();
            await fetchConversations();
          } catch (err) {
            authError.value = err.response?.data || '登录失败，请检查用户名和密码';
          } finally {
            authLoading.value = false;
          }
        };

        const doRegister = async () => {
          authLoading.value = true;
          try {
            const params = new URLSearchParams();
            params.append('username', authForm.value.username);
            params.append('password', authForm.value.password);
            const res = await axios.post('/register', params);
            userInfo.value = res.data.username;
            isLoggedIn.value = true;
            localStorage.setItem('isLoggedIn', '1');
            localStorage.setItem('username', res.data.username);
            showLoginModal.value = false;
            await fetchDomains();
          } catch (err) {
            authError.value = err.response?.data || '注册失败，请检查输入信息';
          } finally {
            authLoading.value = false;
          }
        };

        const handleAuth = () => {
          if (authMode.value === 'login') {
            doLogin();
          } else {
            doRegister();
          }
        };

        // 页面加载时判断登录状态
        const checkLogin = async () => {
          try {
            const res = await axios.get('/me');
            userInfo.value = res.data.username;
            isLoggedIn.value = true;
            localStorage.setItem('isLoggedIn', '1');
            localStorage.setItem('username', res.data.username);
            await fetchDomains();
            await fetchConversations();
          } catch {
            isLoggedIn.value = false;
            userInfo.value = '';
            localStorage.removeItem('isLoggedIn');
            localStorage.removeItem('username');
          }
        };

        checkLogin(); // 页面初始化时调用

        fetchDomains();
        fetchConversations();

        window.showLoginModal = showLoginModal;

        return {
          domains,
          selectedDomain,
          conversations,
          selectedConversation,
          chatHistory,
          input,
          loading,
          filteredConversations,
          sendMessage,
          onDomainChange,
          selectConversation,
          renderMarkdown,
          showLogin,
          logout,
          showLoginModal,
          userInfo,
          isLoggedIn,
          authMode,
          authForm,
          authLoading,
          authError,
          handleAuth,
          showRegister
        };
      }
    }).mount('#app');
</script>
</body>
</html>
